﻿/* EntitiesToDTOs. Copyright (c) 2011. Fabian Fernandez.
 * http://entitiestodtos.codeplex.com
 * Licensed by Common Development and Distribution License (CDDL).
 * http://entitiestodtos.codeplex.com/license
 * Fabian Fernandez. 
 * http://www.linkedin.com/in/fabianfernandezb/en
 * */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EntitiesToDTOs.Generators.Parameters;
using System.Xml.Linq;
using EntitiesToDTOs.Properties;
using System.IO;
using EntitiesToDTOs.Enums;

namespace EntitiesToDTOs.Helpers
{
    /// <summary>
    /// Helps in the tasks relative to the User Configuration.
    /// </summary>
    internal class ConfigurationHelper
    {
        /// <summary>
        /// Gets the temporary configuration file path.
        /// </summary>
        public static string TempFilePath
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_tempFilePath))
                {
                    _tempFilePath = Path.GetTempPath() +
                        Resources.EntitiesToDTOsUserConfigTempFileName + 
                        Resources.EntitiesToDTOsUserConfigFileExtension;
                }

                return _tempFilePath;
            }
        }
        private static string _tempFilePath;


        /// <summary>
        /// Exports the User Configuration to the specified file path.
        /// </summary>
        /// <param name="generatorParams">GeneratorManagerParams containing necessary information.</param>
        /// <param name="filePath">File path to export.</param>
        public static void Export(GeneratorManagerParams generatorParams, string filePath)
        {
            // Check correct file extension
            if (filePath.EndsWith(Resources.EntitiesToDTOsUserConfigFileExtension) == false)
            {
                filePath += Resources.EntitiesToDTOsUserConfigFileExtension;
            }

            // Generate export file
            var exportDoc = new XDocument();
            exportDoc.Add(
                new XElement(ConfigNodes.Root,
                    new XElement(ConfigNodes.GenerateAssemblers, generatorParams.GenerateAssemblers),
                    new XElement(ConfigNodes.DTOsConfig,
                        new XElement(ConfigNodes.TargetProjectName, generatorParams.DTOsParams.TargetProject.Name),
                        new XElement(ConfigNodes.EDMXName, generatorParams.DTOsParams.EDMXProjectItem.Name),
                        new XElement(ConfigNodes.GenerateFilter,
                            new XAttribute(ConfigNodes.GenerateFilterAttrAll, generatorParams.DTOsParams.GenerateAllTypes),
                            new XAttribute(ConfigNodes.GenerateFilterAttrComplex, generatorParams.DTOsParams.GenerateAllComplexTypes),
                            new XAttribute(ConfigNodes.GenerateFilterAttrEntities, generatorParams.DTOsParams.GenerateAllEntityTypes)),
                        new XElement(ConfigNodes.SourceFileHeaderComment, generatorParams.DTOsParams.SourceFileHeaderComment),
                        new XElement(ConfigNodes.UseProjectDefaultNamespace, generatorParams.DTOsParams.UseProjectDefaultNamespace),
                        new XElement(ConfigNodes.SourceNamespace, generatorParams.DTOsParams.SourceNamespace),
                        new XElement(ConfigNodes.DTOsServiceReady, generatorParams.DTOsParams.DTOsServiceReady),
                        new XElement(ConfigNodes.SourceFileGenerationType, generatorParams.DTOsParams.SourceFileGenerationType),
                        new XElement(ConfigNodes.SourceFileName, generatorParams.DTOsParams.SourceFileName),
                        new XElement(ConfigNodes.AssociationType, generatorParams.DTOsParams.AssociationType),
                        new XElement(ConfigNodes.GenerateDTOConstructors, generatorParams.DTOsParams.GenerateDTOConstructors),
                        new XElement(ConfigNodes.ClassIdentifier, 
                            new XAttribute(ConfigNodes.ClassIdentifierAttrUse, generatorParams.DTOsParams.ClassIdentifierUse.ToString()),
                            new XAttribute(ConfigNodes.ClassIdentifierAttrWord, generatorParams.DTOsParams.ClassIdentifierWord))
                    ),
                    new XElement(ConfigNodes.AssemblersConfig,
                        new XElement(ConfigNodes.TargetProjectName, generatorParams.AssemblersParams.TargetProject.Name),
                        new XElement(ConfigNodes.SourceFileHeaderComment, generatorParams.AssemblersParams.SourceFileHeaderComment),
                        new XElement(ConfigNodes.UseProjectDefaultNamespace, generatorParams.AssemblersParams.UseProjectDefaultNamespace),
                        new XElement(ConfigNodes.SourceNamespace, generatorParams.AssemblersParams.SourceNamespace),
                        new XElement(ConfigNodes.SourceFileGenerationType, generatorParams.AssemblersParams.SourceFileGenerationType),
                        new XElement(ConfigNodes.SourceFileName, generatorParams.AssemblersParams.SourceFileName),
                        new XElement(ConfigNodes.IsServiceReady, generatorParams.AssemblersParams.IsServiceReady),
                        new XElement(ConfigNodes.ClassIdentifier,
                            new XAttribute(ConfigNodes.ClassIdentifierAttrUse, generatorParams.AssemblersParams.ClassIdentifierUse.ToString()),
                            new XAttribute(ConfigNodes.ClassIdentifierAttrWord, generatorParams.AssemblersParams.ClassIdentifierWord))
                    )
                )
            );

            // Get generate filter node
            XElement genFilterNode = exportDoc.Descendants(ConfigNodes.GenerateFilter).First();

            // Add filter type nodes
            foreach (string typeName in generatorParams.DTOsParams.TypesToGenerateFilter)
            {
                genFilterNode.Add(new XElement(ConfigNodes.GenerateType, 
                    new XAttribute(ConfigNodes.GenerateTypeAttrName, typeName))
                );
            }

            // Save export file
            exportDoc.Save(filePath);
        }

        /// <summary>
        /// Imports a User Configuration from the specified file path.
        /// </summary>
        /// <param name="filePath">File path from where to read the User Configuration.</param>
        /// <returns></returns>
        public static GeneratorManagerParams Import(string filePath)
        {
            // Prepare result
            var result = new GeneratorManagerParams();
            result.DTOsParams = new GenerateDTOsParams();
            result.AssemblersParams = new GenerateAssemblersParams();

            // Load the config file
            var configXML = XDocument.Load(filePath);

            // Get general config
            result.GenerateAssemblers = (configXML.Descendants(ConfigNodes.GenerateAssemblers).First().Value == Resources.XmlBoolTrue);

            #region DTOs
            // Get the DTOs config node
            XElement dtosConfigNode = configXML.Descendants(ConfigNodes.DTOsConfig).First();
            result.DTOsParams.TargetProjectName = dtosConfigNode.Descendants(ConfigNodes.TargetProjectName).First().Value;
            result.DTOsParams.EDMXName = dtosConfigNode.Descendants(ConfigNodes.EDMXName).First().Value;
            result.DTOsParams.SourceFileHeaderComment = dtosConfigNode.Descendants(ConfigNodes.SourceFileHeaderComment).First().Value;
            result.DTOsParams.UseProjectDefaultNamespace = (dtosConfigNode.Descendants(ConfigNodes.UseProjectDefaultNamespace).First().Value == Resources.XmlBoolTrue);
            result.DTOsParams.SourceNamespace = dtosConfigNode.Descendants(ConfigNodes.SourceNamespace).First().Value;
            result.DTOsParams.DTOsServiceReady = (dtosConfigNode.Descendants(ConfigNodes.DTOsServiceReady).First().Value == Resources.XmlBoolTrue);
            result.DTOsParams.SourceFileGenerationType = dtosConfigNode.Descendants(ConfigNodes.SourceFileGenerationType).First().Value;
            result.DTOsParams.SourceFileName = dtosConfigNode.Descendants(ConfigNodes.SourceFileName).First().Value;
            result.DTOsParams.AssociationType = dtosConfigNode.Descendants(ConfigNodes.AssociationType).First().Value;
            result.DTOsParams.GenerateDTOConstructors = (dtosConfigNode.Descendants(ConfigNodes.GenerateDTOConstructors).First().Value == Resources.XmlBoolTrue);

            // Set generate filter defaults
            result.DTOsParams.GenerateAllTypes = true;
            result.DTOsParams.GenerateAllComplexTypes = true;
            result.DTOsParams.GenerateAllEntityTypes = true;
            result.DTOsParams.TypesToGenerateFilter = new List<string>();

            // Generate filter node exists?
            XElement genFilterNode = dtosConfigNode.Descendants(ConfigNodes.GenerateFilter).FirstOrDefault();
            if (genFilterNode != null)
            {
                // Get generation flags
                result.DTOsParams.GenerateAllTypes = 
                    (genFilterNode.Attribute(ConfigNodes.GenerateFilterAttrAll).Value == Resources.XmlBoolTrue);

                result.DTOsParams.GenerateAllComplexTypes = 
                    (genFilterNode.Attribute(ConfigNodes.GenerateFilterAttrComplex).Value == Resources.XmlBoolTrue);

                result.DTOsParams.GenerateAllEntityTypes = 
                    (genFilterNode.Attribute(ConfigNodes.GenerateFilterAttrEntities).Value == Resources.XmlBoolTrue);

                // Get filter types
                foreach (XElement generateTypeNode in genFilterNode.Descendants(ConfigNodes.GenerateType))
                {
                    result.DTOsParams.TypesToGenerateFilter.Add(
                        generateTypeNode.Attribute(ConfigNodes.GenerateTypeAttrName).Value
                    );
                }
            }

            // Set DTOs identifier defaults
            result.DTOsParams.ClassIdentifierUse = ClassIdentifierUseEnum.Suffix;
            result.DTOsParams.ClassIdentifierWord = "DTO";

            // DTO identifier node exists?
            XElement dtosIdentifierNode = dtosConfigNode.Descendants(ConfigNodes.ClassIdentifier).FirstOrDefault();
            if (dtosIdentifierNode != null)
            {
                string dtoIdentifierUseValue = dtosIdentifierNode.Attribute(ConfigNodes.ClassIdentifierAttrUse).Value;

                if (dtoIdentifierUseValue == ClassIdentifierUseEnum.None.ToString())
                {
                    result.DTOsParams.ClassIdentifierUse = ClassIdentifierUseEnum.None;
                }
                else if (dtoIdentifierUseValue == ClassIdentifierUseEnum.Prefix.ToString())
                {
                    result.DTOsParams.ClassIdentifierUse = ClassIdentifierUseEnum.Prefix;
                }

                result.DTOsParams.ClassIdentifierWord = dtosIdentifierNode.Attribute(ConfigNodes.ClassIdentifierAttrWord).Value;
            }
            #endregion DTOs

            #region Assemblers
            // Get the Assemblers config node
            XElement assemblersConfigNode = configXML.Descendants(ConfigNodes.AssemblersConfig).First();
            result.AssemblersParams.TargetProjectName = assemblersConfigNode.Descendants(ConfigNodes.TargetProjectName).First().Value;
            result.AssemblersParams.SourceFileHeaderComment = assemblersConfigNode.Descendants(ConfigNodes.SourceFileHeaderComment).First().Value;
            result.AssemblersParams.UseProjectDefaultNamespace = (assemblersConfigNode.Descendants(ConfigNodes.UseProjectDefaultNamespace).First().Value == Resources.XmlBoolTrue);
            result.AssemblersParams.SourceNamespace = assemblersConfigNode.Descendants(ConfigNodes.SourceNamespace).First().Value;
            result.AssemblersParams.SourceFileGenerationType = assemblersConfigNode.Descendants(ConfigNodes.SourceFileGenerationType).First().Value;
            result.AssemblersParams.SourceFileName = assemblersConfigNode.Descendants(ConfigNodes.SourceFileName).First().Value;
            result.AssemblersParams.IsServiceReady = (assemblersConfigNode.Descendants(ConfigNodes.IsServiceReady).First().Value == Resources.XmlBoolTrue);

            // Set Assemblers identifier defaults
            result.AssemblersParams.ClassIdentifierUse = ClassIdentifierUseEnum.Suffix;
            result.AssemblersParams.ClassIdentifierWord = "Assembler";

            // DTO identifier node exists?
            XElement assemblersIdentifierNode = assemblersConfigNode.Descendants(ConfigNodes.ClassIdentifier).FirstOrDefault();
            if (assemblersIdentifierNode != null)
            {
                string assemblersIdentifierUseValue = assemblersIdentifierNode.Attribute(ConfigNodes.ClassIdentifierAttrUse).Value;

                if (assemblersIdentifierUseValue == ClassIdentifierUseEnum.None.ToString())
                {
                    result.AssemblersParams.ClassIdentifierUse = ClassIdentifierUseEnum.None;
                }
                else if (assemblersIdentifierUseValue == ClassIdentifierUseEnum.Prefix.ToString())
                {
                    result.AssemblersParams.ClassIdentifierUse = ClassIdentifierUseEnum.Prefix;
                }

                result.AssemblersParams.ClassIdentifierWord = assemblersIdentifierNode.Attribute(ConfigNodes.ClassIdentifierAttrWord).Value;
            }
            #endregion Assemblers

            // Return the configuration
            return result;
        }
    }
}